package com.hwadee.ems.service.impl;

import java.util.List;
import java.util.stream.Collectors;

import jakarta.annotation.Resource;
import jakarta.annotation.PostConstruct;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.hwadee.ems.domain.dto.Result;
import com.hwadee.ems.domain.dto.PageQuery;
import com.hwadee.ems.domain.po.Course;
import com.hwadee.ems.domain.po.TrainingProgram;
import com.hwadee.ems.domain.po.TrainingProgramCourse;
import com.hwadee.ems.domain.vo.CourseVO;
import com.hwadee.ems.mapper.TrainingProgramCourseMapper;
import com.hwadee.ems.service.ICourseService;
import com.hwadee.ems.service.ITrainingProgramService;

import com.hwadee.ems.service.ITrainingProgramCourseService;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * <p>
 * 人才培养方案课程 服务实现类
 * </p>
 *
 * @author EnosElinsa
 * @since 2024/06/21
 */
@Service
public class TrainingProgramCourseServiceImpl extends ServiceImpl<TrainingProgramCourseMapper, TrainingProgramCourse> implements ITrainingProgramCourseService {

    private static ITrainingProgramCourseService instance;

    public static ITrainingProgramCourseService getInstance() {
        return instance;
    }

    @PostConstruct
    void init() {
        instance = this;
    }

    @Resource
    private ICourseService courseService;

    @Resource
    private ITrainingProgramService trainingProgramService;

    @Override
    public Result<IPage<CourseVO>> pageByTrainingProgramId(
        PageQuery pageQuery,
        Long trainingProgramId, 
        Long category,
        Long semesterId,
        Long selectionMethod,
        Long assessmentMethod
    ) {
        List<Long> courseIds = lambdaQuery().eq(TrainingProgramCourse::getTrainingProgramId, trainingProgramId)
            .list()
            .stream()
            .map(TrainingProgramCourse::getCourseId)
            .collect(Collectors.toList());

        var wrapper = Wrappers.lambdaQuery(Course.class)
           .in(Course::getId, courseIds)
           .eq(category != null, Course::getCategory, category)
           .eq(semesterId != null, Course::getSemesterId, semesterId)
           .eq(selectionMethod != null, Course::getSelectionMethod, selectionMethod)
           .eq(assessmentMethod != null, Course::getAssessmentMethod, assessmentMethod);

        return Result.ok(
            courseService.page(Page.of(pageQuery.getCurrent(), pageQuery.getSize()), wrapper)
               .convert(CourseVO::new)
        );
    }

    @Override
    @Transactional
    public Result<Long> saveWithCourseCountIncrement(TrainingProgramCourse trainingProgramCourse) {
        Long count = lambdaQuery().eq(TrainingProgramCourse::getCourseId, trainingProgramCourse.getCourseId())
            .eq(TrainingProgramCourse::getTrainingProgramId, trainingProgramCourse.getTrainingProgramId())
            .count();
        if (count > 0) {
            return Result.error("课程已存在于该培养方案中");
        }
        if (save(trainingProgramCourse)) {
            trainingProgramService.lambdaUpdate()
                .eq(TrainingProgram::getId, trainingProgramCourse.getTrainingProgramId())
                .setIncrBy(TrainingProgram::getCourseCount, 1)
                .update();
            return Result.ok(trainingProgramCourse.getId());
        } else {
            return Result.error();
        }
    }

    @Override
    @Transactional
    public Result<Void> removeByIdWithCourseCountDecrement(TrainingProgramCourse trainingProgramCourse) {
        Long id = lambdaQuery()
            .eq(TrainingProgramCourse::getCourseId, trainingProgramCourse.getCourseId())
            .eq(TrainingProgramCourse::getTrainingProgramId, trainingProgramCourse.getTrainingProgramId())
            .oneOpt()
            .map(TrainingProgramCourse::getId)
            .orElse(null);
        if (id!= null && removeById(id)) {
            trainingProgramService.lambdaUpdate()
                .eq(TrainingProgram::getId, trainingProgramCourse.getTrainingProgramId())
                .setDecrBy(TrainingProgram::getCourseCount, 1)
                .update();
            return Result.ok();
        } else {
            return Result.error();
        }
    }

}
